Gulp 构建工具

项目构建是指项目上线之前对项目源代码进行一系列处理,使其以最佳的形式运行于线上服务器。常见处理任包括以下几方面:

1、模块化开发可以实现功能的复用并解决模块间的依赖关系,但带来好处的同时也使得功能代码的碎片化(若干文件)程度增加。

2、使用less、sass等预处理器,可以降低CSS的维护成本,最终需要将这些预处理器编译成css文件;

3、对静态资源(css、js、html、images)压缩合并可以提升网页打开速度,提高性能;

以上任务完如果完全靠手动来完成是非常耗时耗力的且容易出错,实际开发通常借助构建工具来实现。

所谓构建工具是指通过一系简单配置就可以帮我们实现合并、压缩、校验、预处理等一系列任务的软件工具。

常见的构建工具包括:Grunt、Gulp、F.I.S(百度出品)、webpack等。

Gulp是基于 Nodejs 开发的一个构建工具,借助 gulp 插件可以实现不同的构建任务,其以简洁的配置和卓越的性能成为目前主流的构建工具。

全局安装

1
$ npm install -g gulp

Gulp基础

1、本地安装 gulp

进入项目根目录执行

1
$ npm install gulp --save-dev

2、全局安装

1
$ npm install -g gulp

添加–save-dev会在package.json记录依赖关系.

3、任务清单

在项目根目录中创建 gulpfile.js,gulp会参考这个配置文件执行构建任务。

4、定义任务

gulpfile.js定义构建任务,如压缩、合并等。

gulp 是通过调用插件来完成具体构建任务的,并且这些插件也都基于 Nodejs.

以编译 LESS 为例,安装

1
$ npm install gulp-less

使用 gulp, 定义了一个名称为 less 的任务,用来完成 less 编译成 css 的任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
var gulp = require('gulp');
var less = require('gulp-less');
// 定义任务 参数[名称,回调函数]
gulp.task('less', function(){
// 获取想要转换的路径,相对路径
// 用来找到要构建的资源 参数[资源路径]
gulp.src('./public/less/*.less')
// 将资源传给插件 参数[插件调用]
.pipe(less())
// 存放路径 将构建的好的资源重新存储 参数[路径]
.pipe(gulp.dest('./release/css'));
;
});

5、执行任务

打开命令行窗口并切换到项目根目录下,执行命令 gulp less,这时全局安装的 gulp 便以我们定义好的 gulpfile.js 执行构建任务了。

这样LESS文件便会编译成CSS文件,并保存在了./public/css目录下。

各种插件的使用:

Gulp工作原理

通过不同的插件实现构建任务,Gulp只是按着配置文件调用执行了这些插件。

Gulp API

Gulp是基于NodeJS的,通过require可以引入一个NodeJS的包(模块),其作用类似于浏览器中的script标签引入资源,被引入的包存放在node_modules目录下。

引入gulp包(模块)后返回一个对象(习惯赋值给变量gulp),通过该对象提供的方法(API)完成任务的配置。

1、gulp.task()

定义各种不同的任务,不同任务间存在依赖关系时,可以指定依赖。

2、gulp.src()

需要构建资源的路径,字符串或数组(可以正则方式书写)

2、gulp.pipe()

管道,将需要构建的资源“输送”给插件。

3、gulp.dest()

构建任务完成后资源存放的路径(会自动创建)

4、gulp.watch()

通过监视某静态资源的修改,然后可以调用相应任务。

常用Gulp插件

  • gulp-less
    • 编译LESS文件
  • gulp-autoprefixer
    • 添加CSS私有前缀
  • gulp-cssmin
    • 压缩CSS
  • gulp-rname
    • 重命名
  • gulp-imagemin
    • 图片压缩
  • gulp-uglify
    • 压缩Javascript
  • gulp-concat
    • 合并
  • gulp-htmlmin
    • 压缩HTML
  • gulp-rev
    • 添加版本号
  • gulp-rev-collector
    • 内容替换
  • gulp-useref
  • gulp-if
  • gulp-seajs-transport

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 引包
// 在 node-modules 下找
var gulp = require('gulp'),
// 删除文件的
clean = require('gulp-clean'),
// 添加 idleading
transport = require('gulp-seajs-transport'),
concat = require('gulp-seajs-concat'),
less = require('gulp-less'),
cssmin = require('gulp-cssmin'),
autoprefixer = require('gulp-autoprefixer'),
imagemin = require('gulp-imagemin'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat'),
htmlmin = require('gulp-htmlmin'),
rev = require('gulp-rev'),
revCollector = require('gulp-rev-collector'),
useref = require('gulp-useref'),
gulpif = require('gulp-if'),
rename = require('gulp-rename'),
base64 = require('gulp-base64');
gulp.task('clean', function() {
// 路径相对于 gulpfile,跟 node 没关系
return gulp.src('./public/dist')
.pipe(clean());
});
// 添加 idleading
gulp.task('transport', ['clean'], function() {
gulp.src('./public/!(libs)/**/*.js')
.pipe(transport({
idleading: './public/dist/'
}))
.pipe(concat())
.pipe(uglify())
.pipe(gulp.dest('./public/dist'))
});
// css 任务
gulp.task('less2css', function(){
return gulp.src('./public/less/*.less')
.pipe(less())
.pipe(cssmin())
// 处理 CSS 中的图片为 base64
.pipe(base64())
.pipe(autoprefixer())
// 资源后缀改了,文件里的路径也需要改变,利用 gulp-rev-collector
// 先改名并存储,然后再替换
.pipe(rev())
.pipe(gulp.dest('./release/css'))
.pipe(rev.manifest())
.pipe(rename('css-mainfest.json'))
// 收集替换前后的关系
.pipe(gulp.dest('./release/rev'));
});
// 图片任务
// 构建过程中需要保证图片路是不变的
// src 有第二个参数,是一个对象
// 在 images 下面还有目录,那么这样还有问题
// 在加一个*,表示有多少层目录,都给我能找到
gulp.task('image', function(){
return gulp.src(['./images/**/*', './uploads/**/*'], {base: './'})
.pipe(imagemin())
.pipe(rev())
.pipe(gulp.dest('./release'))
.pipe(rev.manifest())
.pipe(rename('image-mainfest.json'))
.pipe(gulp.dest('./release/images'));
});
// js 资源
gulp.task('js', function(){
gulp.src('./libs/*.js')
.pipe(uglify())
// 合并,需要传参数,合并后的名称
.pipe(concat('all.js'))
.pipe(gulp.dest('./release/libs'));
});
// html 资源
gulp.task('html', function(){
gulp.src('./view/*.html')
// 需要参数,去掉空间,注释,压缩 js 代码
.pipe(htmlmin({
collapseWhitespace:true,
removeComments:true,
minifyJs: true
}))
.pipe(gulp.dest('./release/views'));
});
// 替换任务
gulp.task('revCollector', function(){
// 按照哪个标准去替换 两个参数
// 文件
// 替换哪个文件
gulp.src(['./release/rev/*.json', './release/*.html'])
.pipe(revCollector())
.pipe(gulp.dest('./release'));
});
// 页面中还引入了 jQuery,想要让两个文件做一个合并,前面的 gulp-concat 插件有点问题,还需要我们手动修改路径。
// 压缩合并处理路径任务,md5
gulp.task('useref', function(){
return gulp.src('./index.html')
// 找到 build 标记的内容,合并并替换
.pipe(useref())
// 假如是以 js 结尾的,合并并压缩,那么再调用下一个插件
// uglify 只能压缩 js 文件,使用 gulp-if 插件过滤 js 文件
.pipe(gulpif('*.js', uglify()))
// 静态资源改名字
.pipe(gulpif('*.js', rev()))
.pipe(gulp.dest('./release'))
// 做一个收集,合并前后的文件名称变化
.pipe(rev.manifest())
// 为了避免替换
.pipe(rename('js-manifest.json'))
.pipe(gulp.dest('./release/rev'));
});
// 其它内容
gulp.task('other', function() {
gulp.src(['./api/*', './public/font/*'], {base: './'})
.pipe(gulp.dest('./release'));
});
// 路径替换
gulp.task('rev', ['css', 'image', 'useref'], function () {
gulp.src(['./release/rev/*.json', './release/**/*.?(html|css)'])
.pipe(revCollector())
.pipe(gulp.dest('./release'));
});
gulp.task('default', ['rev', 'other', 'html']);

seajs 的配置文件中加 vars 键修改引入 seajs 文件的路径

1
2
3
4
5
6
7
8
9
seajs.config({
base: './public/asserts',
alias: {
'jquery': 'jQuery/jquery'
},
vars: {
path: 'dist'
}
});

重新配置生产环境(项目上线)文件路径:

1
2
3
4
<script>
// ./public/{path}/scripts/index 这个路径是模块名称需要的
seajs.use('./public/{path}/index');
</script>

bulid 的一个示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- build:js ./libs/all.js -->
<script src="./libs/jquery.min.js"></script>
<script src="./libs/toggle.js"></script>
<!-- endbuild -->
```

## 缓存、性能优化
`<link href="base.css?v=1">`后面的参数用来解决浏览器缓存

浏览器会将静态资源(CSS、images、js)缓存到本地浏览器中,下次请求时就读取本地资源来显示,缓存可以带来性能的提升,但是也会给前端开发者带来问题。往往这种问题是由缓存构成的。

怎么解决呢?分析浏览器缓存机制问题。什么情况下不需要浏览器缓存?

浏览器默认缓存按资源路径进行的缓存 ./css/base.css,因此每次开发加个参数 ./css/base.css?v=1 或者 ./css/base.css?v=20141123 加了一个时间戳;

前端性能优化:`协商缓存,雅虎 13`

当内容的确改变后才需要,就意味着我们需要知道内容是否改变了,利用 md5 可以处理。当更改后会形成新的值,利用这个值充当文件名称。把文件加密成 md5 串,这种方式就是指纹

## 不同 js 文件合并
需要注释:` ./libs/all.js `就是合并之后的名称

```js
<!-- build:js ./libs/all.js -->
<script src='./libs/jquery.min.js'></script>
<script src='./libs/toggle.js'></script>
<!-- endbuild -->

移除一些上线不需要的文件。

1
2
3
4
5
6
7
8
9
10
<!-- 并没有实际合并,而是利用 build:css 来改名称 -->
<!-- build:css ./public/css/main.css -->
<link rel="stylesheet" href="./public/less/main.less">
<!-- endbuild -->
<!-- build:remove -->
<script src="./public/less/less.js"></script>
<!-- endbuild -->
<!-- build:remove -->
<script src='./libs/less.js'></script>
<!-- endbuild -->

合并之后压缩

.pipe(gulpif('*.js', uglify()))

gulp 构建过程总结

  • touch gulpfile.js
  • 全局安装 gulp
  • 本地安装 gulp
  • 处理 css
    • gulp-less
    • gulp-cssmin
    • gulp-autoprefixer
    • gulp-rev
    • rev.minifest() 改名称了
    • gulp-rename
  • 图片处理
    • gulp-imagemin
    • gulp-rename
  • 改名
    • gulp-useref
    • gulp-manifest
    • gulp-uglify
    • gulp-if
  • 路径替换
    • gulp-rev-collector
  • 压缩 html
    • gulp-htmlmin
  • 处理一些其它内容

监视文件变化

1
2
3
4
5
gulp.task('watch', function(){
// 可以用这个 watch 来实现实时编译的功能
gulp.watch('./index.html',['default'], function(event){
});
});

文件合并时需要对每一个模块娶一个名字

需要一个工具

seajs 在上线做合并处理的时候,并不是将所有文件合并才是最佳方式,
有一些公共第三方模块可以不做合并处理,利用浏览器缓存功能更会使得性能更好;

define(‘当前模块路径’, [‘依赖模块相对路径’], function() {});

要实现上述操作,需要在合并前

感谢您的支持!
0%